"""知识图谱增强检索问答系统的Web服务模块

该模块提供了一个基于FastAPI的Web服务，允许用户上传文件构建知识图谱，
并基于知识图谱进行问答。支持多种文件格式，并提供API接口供前端调用。

主要功能：
1. 文件上传和知识图谱构建
2. 基于知识图谱的问答
3. 上传文件列表查询
4. 静态文件服务

依赖：pip install python-multipart
"""

from fastapi import FastAPI, UploadFile, File, Form, HTTPException
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles
from pathlib import Path
import os
import shutil
import json
from typing import List, Dict, Optional
from rag_core import build_kg_from_file, ask_question_with_kg
from utils import get_logger, register_exception_handlers, FileProcessingError, KnowledgeGraphError, LLMError
from config import settings

# 初始化日志记录器
logger = get_logger('main')

app = FastAPI(
    title=settings.APP_NAME,
    description=settings.APP_DESCRIPTION,
    version=settings.APP_VERSION,
    debug=settings.DEBUG
)

# 注册错误处理器
register_exception_handlers(app)
app.mount("/static", StaticFiles(directory="static"), name="static")

# 使用配置模块中的上传目录设置
UPLOAD_FOLDER = settings.UPLOAD_DIR

chat_history = []

@app.post("/api/ask")
async def ask(
    file: Optional[UploadFile] = File(None),
    question: str = Form(...),
    history: Optional[str] = Form(None)
):
    """处理问题并返回答案"""
    global chat_history
    
    logger.info(f"收到问题: {question}")
    
    # 解析历史记录
    if history:
        try:
            chat_history = json.loads(history)
            logger.debug(f"解析历史记录: {len(chat_history)} 条对话")
        except json.JSONDecodeError as e:
            logger.error(f"解析历史记录失败: {str(e)}")
            chat_history = []
    
    # 处理文件上传
    file_path = None
    if file:
        try:
            file_path = UPLOAD_FOLDER / file.filename
            logger.info(f"上传文件: {file.filename}")
            with open(file_path, "wb") as buffer:
                shutil.copyfileobj(file.file, buffer)
            logger.debug(f"文件保存到: {file_path}")
        except Exception as e:
            logger.error(f"文件上传失败: {str(e)}")
            raise FileProcessingError(f"文件上传失败: {str(e)}")
    
    # 构建知识图谱
    triples = []
    if file_path:
        try:
            logger.info(f"从文件构建知识图谱: {file_path}")
            triples = build_kg_from_file(file_path)
            logger.debug(f"提取到 {len(triples)} 个三元组")
        except Exception as e:
            logger.error(f"构建知识图谱失败: {str(e)}")
            raise KnowledgeGraphError(f"构建知识图谱失败: {str(e)}")
    
    # 回答问题
    try:
        logger.info("开始回答问题")
        answer = ask_question_with_kg(question, triples)
        logger.debug(f"回答: {answer[:100]}..." if len(answer) > 100 else f"回答: {answer}")
    except Exception as e:
        logger.error(f"回答问题失败: {str(e)}")
        raise LLMError(f"回答问题失败: {str(e)}")
    
    # 更新聊天历史
    chat_history.append({"question": question, "answer": answer})
    logger.debug(f"更新聊天历史，当前共 {len(chat_history)} 条对话")
    
    # 返回结果
    return {
        "answer": answer,
        "triples": triples,
        "history": chat_history
    }

@app.get("/api/uploads")
async def list_uploads():
    """列出已上传的文件"""
    logger.info("获取上传文件列表")
    files = []
    try:
        for file_path in UPLOAD_FOLDER.glob("*"):
            if file_path.is_file():
                files.append({
                    "name": file_path.name,
                    "path": str(file_path),
                    "size": file_path.stat().st_size,
                    "created": file_path.stat().st_ctime
                })
        logger.debug(f"找到 {len(files)} 个上传文件")
    except Exception as e:
        logger.error(f"获取上传文件列表失败: {str(e)}")
        raise FileProcessingError(f"获取上传文件列表失败: {str(e)}")
    return {"files": files}

@app.get("/")
async def root():
    """返回首页"""
    logger.info("访问首页")
    return FileResponse("static/index.html")

if __name__ == "__main__":
    import uvicorn
    
    logger.info(f"启动服务器: {settings.HOST}:{settings.PORT}")
    uvicorn.run(app, host=settings.HOST, port=settings.PORT)
